﻿using System;
using Ewk.Math.Algebra.Algorithms.Matrices;
using Ewk.Math.Algebra.Algorithms.Matrices.Determinant;
using Ewk.Math.ComputationTypes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace Ewk.Math.Algebra.UnitTests.Determinant.DeterminantManipulationsTests.Int32Tests
{
    [TestClass]
    public class MultiplyMatrixInt32Tests : DeterminantManipulationsInt32Base
    {
        protected override void AdditionalSetup()
        {
            base.AdditionalSetup();

            // Define the return value of the DeterminantManipulator in case the matrix gets multiplied by 2
            DeterminantManipulator
                .Expect(matrixManipulations => matrixManipulations.Multiply(2))
                .Return(8);
            DeterminantManipulator.Replay();
        }

        [TestMethod]
        public void When_Multiply_Is_Called_With_A_Matrix_Then_The_Value_Of_The_Determinant_Must_Sized()
        {
            var matrix = Matrix * 2;
            var determinant = CreateComputable(8);

            DeterminantComputer
                .Expect(computer => computer.ComputeDeterminant(matrix))
                .Return(determinant);
            DeterminantComputer.Replay();

            IMatrixManipulations<int, Computable<int>> manipulations = new DeterminantManipulator<int>(Matrix, Determinant);
            var result = manipulations.Multiply(matrix);

            for (var i = 0; i < matrix.RowCount; i++)
            {
                for (var j = 0; j < matrix.ColumnCount; j++)
                {
                    Assert.AreEqual(matrix[i, j], 2*Matrix[i, j]); // Entries remain untouched
                }
            }

            Assert.AreEqual(determinant, result.Value);
        }

        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void When_Multiply_Is_Called_With_Null_Then_An_ArgumentNullException_Is_Thrown()
        {
            IMatrixManipulations<int, Computable<int>> manipulations = new DeterminantManipulator<int>(Matrix, Determinant);
            manipulations.Multiply((Matrix<int>)null);
        }

        [TestMethod]
        public void When_Multiply_Is_Called_With_A_Matrix_And_A_Null_Determinant_Then_The_Result_Is_Null()
        {
            var matrix = Matrix * 2;
            var determinant = CreateComputable(8);

            DeterminantComputer
                .Expect(computer => computer.ComputeDeterminant(matrix))
                .Return(determinant);
            DeterminantComputer.Replay();

            IMatrixManipulations<int, Computable<int>> manipulations = new DeterminantManipulator<int>(Matrix, null);
            var result = manipulations.Multiply(matrix);

            for (var i = 0; i < matrix.RowCount; i++)
            {
                for (var j = 0; j < matrix.ColumnCount; j++)
                {
                    Assert.AreEqual(matrix[i, j], 2 * Matrix[i, j]); // Entries remain untouched
                }
            }

            Assert.IsNull(result);
        }
    }
}